#include "player.h"

#include <SDL/SDL_gfxPrimitives.h>
#include "viewport.h"
#include "spriteManager.h"
#include "explodingSprite.h"
#include "hud.h"
#include "bullet.h"
#include "utils.h"

Player::Player(const string& n) :
	io(IOManager::getInstance()),
	name(n),
	sprite(new MultiSprite(name)),
	hook(new Sprite("hook")),
	grappling(false),
	score(0),
	health(100),
	health_dx (((float)sprite->getFrame()->getWidth()) / 100.0),
	r(0),g(255),b(0),
	playerDead(0),
	godMode(false),
	jumped(false),
	shotsFired(0),
	shotsHit(0)
{
	sprite->setRestitution(0.1);
	sprite->setFriction(0.4);
	sprite->setMass(10);
	hook->setOwner(sprite);
	hook->setCollideWithDynamic(false);
	hook->setIgnoreGravity(true);
	SpriteManager::getInstance().addObject(sprite);
}

Player::~Player()
{
	// If the grappling hook is not being managed by the SpriteManager delete it
	if(!grappling) {
		delete hook;
	}
}

void Player::update()
{
	
}

void Player::draw()
{
	if(playerDead == 1) return;

	Vector2f offset(Viewport::getInstance().X(),Viewport::getInstance().Y());

	// Draw the sprite
	//sprite->draw();

	// Draw the grappling hook
	if(grappling) {
		Vector2f c1 = sprite->getCenter() - offset;
		Vector2f c2 = hook->getCenter() - offset;
		aalineRGBA(IOManager::getInstance().getScreen(), c1[0], c1[1], c2[0], c2[1], 255,0,255,255); 
	}

	// Draw the health bar (x1,y1)top right to (x2,y2)bottom left
	int x1 = sprite->X()-offset[0] + (health_dx * health);
	int y1 = sprite->Y()-offset[1] - 10;

	int x2 = sprite->X()-offset[0];
	int y2 = sprite->Y()-offset[1] - 5;

	boxRGBA(io.getScreen(),x1,y1,x2,y2,r,g,b,255);
}

void Player::updateHealth()
{
	float color_dx = 255.0/50.0;

	if(health > 50) {
		r = (100.0 - health) * color_dx;
		g = 255;
	} else if(health <= 50) {
		r = 255;
		g = health * color_dx;
	}
	// cout << "(r,g,b) => (" << r << "," << g << "," << b << ") " << health << endl;
}

void Player::handleMouseMotion()
{
	if(playerDead == 1) return;
	sprite->handleMouseMotion();
}

Sprite *Player::getSprite()
{
	return sprite;
}

void Player::shoot()
{
	if(playerDead == 1) return;
	
	if(dynamic_cast<ExplodingSprite *>(sprite))
		return;

	shotsFired++;

	int x, y;
	SDL_GetMouseState(&x, &y);
	Vector2f mouse(x + Viewport::getInstance().X(),y + Viewport::getInstance().Y());
	Vector2f pos = sprite->getCenter();

	// Set initial velocity of the bullet based on the reticle
	Vector2f dir = (mouse - pos).normalize();
	dir = (dir * 400);

	Sprite *bullet = new Bullet(pos, dir, "bullet");
	bullet->setOwner(sprite);
	bullet->setIgnoreGravity(true);
	SDLSound::getInstance()[1];
	SpriteManager::getInstance().addObject(bullet);
}

void Player::shoot(Vector2f &dir)
{
	if(playerDead == 1) return;

	shotsFired++;

	Vector2f pos = sprite->getCenter();

	Sprite *bullet = new Bullet(pos, dir, "bullet");
	bullet->setOwner(sprite);
	bullet->setIgnoreGravity(true);
	SDLSound::getInstance()[1];
	SpriteManager::getInstance().addObject(bullet);
}

void Player::left()
{
	if(playerDead == 1) return;
	
	Vector2f v = sprite->getVelocity();
	if(v[0] > -150) {
		v[0] = -150;
		sprite->setVelocity(v);
	}
}

void Player::right()
{
	if(playerDead == 1) return;
	
	Vector2f v = sprite->getVelocity();
	if(v[0] < 150) {
		v[0] = 150;
		sprite->setVelocity(v);
	}
}

void Player::jump()
{
	if(playerDead == 1) return;

	jumped = true;

	SDLSound::getInstance()[0];
	Vector2f v = sprite->getVelocity();
	if(v[1] > -225) {
		v[1] = -225;
		sprite->setVelocity(v);
	}
}

void Player::attachGrapple()
{
	if(playerDead == 1) return;
	
	grappling = true;

	int x, y;
	SDL_GetMouseState(&x, &y);
	Vector2f mouse(x + Viewport::getInstance().X(),y + Viewport::getInstance().Y());
	Vector2f pos = sprite->getCenter();

	// Set initial velocity of the grapple based on the reticle
	Vector2f dir = (mouse - pos).normalize();
	dir = (dir * 1000) + sprite->getVelocity();

	hook->setPosition(pos);
	hook->setVelocity(dir);
	hook->setType(TYPE_DYNAMIC);
	SpriteManager::getInstance().addObject(hook);
}

void Player::releaseGrapple()
{
	grappling = false;
	sprite->setFriction(0.4);
	SpriteManager::getInstance().removeObject(hook);
}
Sprite *Player::getHook()
{
	return hook;
}

void Player::addScore(int x)
{
	score += x;
}

Uint32 playerDeadCallback(Uint32 interval, void *param)
{
	SDL_Event user_event;

	user_event.type       = SDL_USEREVENT;
	user_event.user.code  = EVENT_PLAYER_DEAD;
	user_event.user.data1 = param;
	user_event.user.data2 = NULL;
	interval = 0;

	SDL_PushEvent(&user_event);

	return interval;
}

void Player::addHealth(int x)
{
	if(godMode)
		return;

	health += x;
	updateHealth();
	health = CLAMP(health, 0, 100);
	
	if(health == 0) {
		getSprite()->setState(STATE_COLLIDING);
		SpriteManager::getInstance().removePuppetController(this);
		playerDead = 1;
		SDL_AddTimer(10, playerDeadCallback, NULL);
		SDL_AddTimer(3000, gameOverCallback, NULL);
	}
}

int Player::getScore()
{
	return score;
}

int Player::getHealth()
{
	return health;
}

void Player::toggleGodMode()
{
	if(godMode)
		godMode = false;
	else
		godMode = true;
}

void Player::shotHit()
{
	shotsHit++;
}

int Player::getShotsFired()
{
	return shotsFired;
}

int Player::getShotsHit()
{
	return shotsHit;
}
